package cn.leaf.calculator;

import cn.leaf.calculator.bean.CalUnitBeanDefinition;
import cn.leaf.calculator.bean.ParameterBeanDefinition;
import cn.leaf.calculator.datasource.CalUnitDataSource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.Assert;

import java.io.Serializable;
import java.util.Collection;
import java.util.Map;

/**
 * 抽象的公式计算器
 *
 * @author 李克国
 * @version 1.0.0

 */
@Slf4j
public abstract class AbstractFormulaCalculator<T> implements FormulaCalculator<T> {

    protected CalUnitDataSource<T> dataSources;

    @Override
    public void start() {
        Assert.notNull(dataSources, "CalHelperStartException:未绑定数据源");
        log.info("公式计算器：启动");
        dataSources.initialize();
        log.info("公式计算器：初始化完成");
        while (dataSources.hasNext()) {
            execute(dataSources.next());
        }
        log.info("公式计算器：计算完成");
    }

    @Override
    public void setDataSource(CalUnitDataSource<T> dataSource) {
        this.dataSources = dataSource;
    }

    @Override
    public Collection<T> getCalResults() {
        return dataSources.getValues();
    }

    private void execute(CalUnitBeanDefinition<T> beanDefinition) {
        // 计算项为正常：正常计算
        if (CalUnitBeanDefinition.CALUNIT_STATE_CAL == beanDefinition.getState()) {
            beanDefinition.updateState(cal(beanDefinition) ? CalUnitBeanDefinition.CALUNIT_STATE_CALED : CalUnitBeanDefinition.CALUNIT_STATE_CALED_ERROR);
        }
        // 计算项为自身引用：正常计算
        // 计算项在等待区：先计算其参数值
        if (CalUnitBeanDefinition.CALUNIT_STATE_CAL_WAIT == beanDefinition.getState() || CalUnitBeanDefinition.CALUNIT_STATE_CAL_WAIT_SELF_REF == beanDefinition.getState()) {
            Map<Serializable, ParameterBeanDefinition<T>> parameters = beanDefinition.getParameters();
            parameters.forEach((k, p) -> {
                if (p.getId().equals(beanDefinition.getId())) {
                    // 该参数为自身，跳过计算
                    return;
                }
                if (p instanceof CalUnitBeanDefinition) {
                    execute((CalUnitBeanDefinition<T>) p);
                }
            });
            beanDefinition.updateState(cal(beanDefinition) ? CalUnitBeanDefinition.CALUNIT_STATE_CALED : CalUnitBeanDefinition.CALUNIT_STATE_CALED_ERROR);
        }
        // 计算项为循环引用：按自然顺序计算
        if (CalUnitBeanDefinition.CALUNIT_STATE_CAL_WAIT_WHILE_REF == beanDefinition.getState()) {
            beanDefinition.updateState(cal(beanDefinition) ? CalUnitBeanDefinition.CALUNIT_STATE_CALED : CalUnitBeanDefinition.CALUNIT_STATE_CALED_ERROR);
        }
    }


    @Override
    public void run() {
        start();
    }
}
